//    Copyright (C) Kherty.  All rights reserved.
#region

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

#endregion

namespace OpenLS.UI.Internals
{
    [DefaultEvent("DragDelta"), Localizability(LocalizationCategory.NeverLocalize)]
    public class PreviewThumb : Control
    {
        // Fields

        public static readonly RoutedEvent DragCompletedEvent = Thumb.DragCompletedEvent.AddOwner(typeof (PreviewThumb));

        public static readonly RoutedEvent DragDeltaEvent = Thumb.DragDeltaEvent.AddOwner(typeof (PreviewThumb));

        public static readonly RoutedEvent DragStartedEvent = Thumb.DragStartedEvent.AddOwner(typeof (PreviewThumb));

        public static readonly DependencyProperty IsDraggingProperty;

        private static readonly DependencyPropertyKey IsDraggingPropertyKey;

        private static DependencyObjectType _dType;
        private Point _originScreenCoordPosition;
        private Point _originThumbPoint;
        private Point _previousScreenCoordPosition;

        static PreviewThumb()
        {
            IsDraggingPropertyKey =
                DependencyProperty.RegisterReadOnly("IsDragging", typeof (bool), typeof (PreviewThumb),
                                                    new FrameworkPropertyMetadata(false,
                                                                                  new PropertyChangedCallback(
                                                                                      OnIsDraggingPropertyChanged)));
            IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty;
            DefaultStyleKeyProperty.OverrideMetadata(typeof (PreviewThumb),
                                                     new FrameworkPropertyMetadata(typeof (PreviewThumb)));
            //_dType = typeof(PreviewThumb); //\\DependencyObjectType.FromSystemTypeInternal(typeof(PreviewThumb));
            FocusableProperty.OverrideMetadata(typeof (PreviewThumb), new FrameworkPropertyMetadata(false));
            EventManager.RegisterClassHandler(typeof (PreviewThumb), Mouse.LostMouseCaptureEvent,
                                              new MouseEventHandler(OnLostMouseCapture));
        }

        [Browsable(false), Category("Appearance"), Bindable(true)]
        public bool IsDragging
        {
            get { return (bool) base.GetValue(IsDraggingProperty); }
            protected set { base.SetValue(IsDraggingPropertyKey, value); }
        }

        // Events
        [Category("Behavior")]
        public event DragCompletedEventHandler DragCompleted
        {
            add { base.AddHandler(DragCompletedEvent, value); }
            remove { base.RemoveHandler(DragCompletedEvent, value); }
        }

        [Category("Behavior")]
        public event DragDeltaEventHandler DragDelta
        {
            add { base.AddHandler(DragDeltaEvent, value); }
            remove { base.RemoveHandler(DragDeltaEvent, value); }
        }

        [Category("Behavior")]
        public event DragStartedEventHandler DragStarted
        {
            add { base.AddHandler(DragStartedEvent, value); }
            remove { base.RemoveHandler(DragStartedEvent, value); }
        }

        // Methods

        public void CancelDrag()
        {
            if (IsDragging)
            {
                if (base.IsMouseCaptured)
                {
                    base.ReleaseMouseCapture();
                }
                base.ClearValue(IsDraggingPropertyKey);
                base.RaiseEvent(new DragCompletedEventArgs(
                                    _previousScreenCoordPosition.X - _originScreenCoordPosition.X,
                                    _previousScreenCoordPosition.Y - _originScreenCoordPosition.Y, true));
            }
        }


        protected virtual void OnDraggingChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        private static void OnIsDraggingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((PreviewThumb) d).OnDraggingChanged(e);
        }

        private static void OnLostMouseCapture(object sender, MouseEventArgs e)
        {
            var thumb = (PreviewThumb) sender;
            if (Mouse.Captured != thumb)
            {
                thumb.CancelDrag();
            }
        }

        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (!IsDragging)
            {
                e.Handled = true;
                base.Focus();
                base.CaptureMouse();
                base.SetValue(IsDraggingPropertyKey, true);
                _originThumbPoint = e.GetPosition(this);
                _previousScreenCoordPosition = _originScreenCoordPosition = e.GetPosition(TopElement());
                var flag = true;
                try
                {
                    base.RaiseEvent(new DragStartedEventArgs(_originThumbPoint.X, _originThumbPoint.Y));
                    flag = false;
                }
                finally
                {
                    if (flag)
                    {
                        CancelDrag();
                    }
                }
            }
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (base.IsMouseCaptured && IsDragging)
            {
                e.Handled = true;
                base.ClearValue(IsDraggingPropertyKey);
                base.ReleaseMouseCapture();
                var point = e.MouseDevice.GetPosition(TopElement());
                base.RaiseEvent(new DragCompletedEventArgs(point.X - _originScreenCoordPosition.X,
                                                           point.Y - _originScreenCoordPosition.Y, false));
            }
            base.OnMouseLeftButtonUp(e);
            e.Handled = true;
        }

        private FrameworkElement TopElement()
        {
            FrameworkElement result = this;
            while (result.Parent != null)
                result = (FrameworkElement) result.Parent;
            return result;
        }

        protected override void OnPreviewMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (IsDragging)
            {


                if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                {
                    var position = e.GetPosition(this);
                    var point2 = e.GetPosition(TopElement());
                    if (point2 != _previousScreenCoordPosition)
                    {
                        _previousScreenCoordPosition = point2;
                        e.Handled = true;
                        base.RaiseEvent(new DragDeltaEventArgs(position.X - _originThumbPoint.X,
                                                               position.Y - _originThumbPoint.Y));
                    }
                }
                else
                {
                    if (e.MouseDevice.Captured == this)
                    {
                        base.ReleaseMouseCapture();
                    }
                    base.ClearValue(IsDraggingPropertyKey);
                    _originThumbPoint.X = 0.0;
                    _originThumbPoint.Y = 0.0;
                }
            }
        }
    }
}